package com.cl.util;

import com.cl.annotation.ClController;
import com.cl.container.ClBean;
import com.cl.annotation.ClComponent;
import com.cl.container.MyContainer;
import com.cl.myInterface.DisposeClass;
import com.cl.postprocessor.IBeanPostProcessor;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/*
* 应该抽出一个 接口 ,这里扫描到各种类后,分发到各种 处理 这些class的具体实现类中去
*
* */
public class ScannerClass {

    public static void scanner(Class clazz) {
        //获取传入的类的包路径
        URL resource = clazz.getResource("");
        File file = new File(resource.getPath());

        ArrayList<String> strings = new ArrayList<>();
        //所有的class文件全路径
        List<String> allClassName = scan(file, strings);

        //类加载器
        ClassLoader classLoader = clazz.getClassLoader();


        /*
        * 获取到所有处理bean的实现类,来处理类 (后续可以用 SPI ,将内置的类放入文件中,默认读取,springboot也是如此)
        * */
        List<DisposeClass> allDisposeClass = new ArrayList<>();
        allClassName.forEach(clasz->{
            String qualifiedClassName = filterQualifiedClassName(clasz);
            if (!qualifiedClassName.equals("")) {
                try {
                    Class<?> clazs = classLoader.loadClass(qualifiedClassName);
                    if (!clazs.isInterface()) {
                        Object o = clazs.getDeclaredConstructor().newInstance();
                        //是否属于处理bean的类
                        if (o instanceof  DisposeClass) {
                            DisposeClass o1 = (DisposeClass) o;
                            System.out.println(o1.order());
                            allDisposeClass.add(o1);
                        }
                    }
                } catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        });

        //对处理类进行排序,以便按照顺序 先加载所有bean,再注入bean
        System.out.println(allDisposeClass);
        List<DisposeClass> disposeClasses = orderDisposeBean(allDisposeClass);
        System.out.println(disposeClasses);


        /*
         * 扫描所有的Class
         * */
        List<Class> allClass = new ArrayList<>();
        allClassName.forEach(clasz -> {
            try {
                //获取类的全限定类名 , 直接用类加载器加载这个全限定类名的类
                String qualifiedClassName = filterQualifiedClassName(clasz);
                if (!qualifiedClassName.equals("")) {
                    Class<?> clazs = classLoader.loadClass(qualifiedClassName);
                    allClass.add(clazs);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        });


        //用所有的处理类 , 来处理class
        disposeClasses.forEach(disposeClass -> {
            disposeClass.dispose(allClass);
        });

        /*
         * 扫描所有的bean的Class
         * */
//        allClassName.forEach(clasz -> {
//            try {
//                //获取类的全限定类名 , 直接用类加载器加载这个全限定类名的类
//                String qualifiedClassName = filterQualifiedClassName(clasz);
//                if (!qualifiedClassName.equals("")) {
//                    Class<?> clazs = classLoader.loadClass(qualifiedClassName);
//                    ClComponent annotation = clazs.getAnnotation(ClComponent.class);
//                    //代表自定义组件
//                    if (annotation != null) {
//                        if (annotation.isBean()) {
//                            //收集所有bean的Class
//                            MyContainer.putInjectClass(annotation.value(), clazs);
//                        }
//                    }
//
//                    //controller 扫描出  key: url , value: class对象
//                    ClController clController = clazs.getAnnotation(ClController.class);
//                    if (clController != null && clController.isController()){
//                        //收集所有controller的Class
//                        MyContainer.putInjectClass(clController.value(), clazs);
//                    }
//                }
//            } catch (ClassNotFoundException e) {
//                e.printStackTrace();
//            }
//        });


//        过滤出各种非普通bean , 例如: 后置处理器 , controller
//        MyContainer.getInjectClassMap().forEach((beanName, beanClazz) -> {
//            if (!beanClazz.isInterface()) {
//                    try {
//                        //根据扫描到的bean的class,过滤出 bean后置处理器
//                        Object o = beanClazz.getDeclaredConstructor().newInstance();
//                        if (o instanceof IBeanPostProcessor) {
//                            //先将bean收集进容器
//                            ClBean clBean = preCreateBean(beanName,beanClazz);
//                            if (clBean != null) {
//                                //收集进后置处理器集合中
//                                MyContainer.putPostProcessor(clBean.getBeanName(), clBean);
//                            }
//                        }
//
//                        //收集controller
//                        ClController annotation = beanClazz.getAnnotation(ClController.class);
//                        if (annotation != null && !annotation.value().equals("") && annotation.isController()){
//                            crateCoController(annotation.value(),beanClazz);
//                        }
//                    } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
//                        e.printStackTrace();
//                    }
//                }
//        });


        /*
         * 初始化bean
         * */
//        MyContainer.getInjectClassMap().forEach((beanName, beanClass) -> {
//            //先将bean收集进容器
//            ClBean clBean = preCreateBean(beanName,beanClass);
//            if (clBean != null) {
//                //装入容器
//                MyContainer.putBean(beanName, clBean);
//            }
//        });



//        /*
//         * 开始注入service的bean
//         * */
//        //将收集到的待注入的所有bean进行注入
//        MyContainer.getContainer().forEach((beanName, clBean) -> {
//            Object object = injectClBean(beanName, clBean.getObject().getClass());
//
//            //用相同的beanName , 把容器中对应的bean给替换掉,因为原来初始化的容器中的bean的需要注入属性都是没有注入的,都是null,
//            //经过这里注入后,替换为已经注入了属性的 bean
//            ClBean clBean1 = new ClBean();
//            clBean1.setBeanName(beanName);
//            clBean1.setObject(object);
//            clBean1.setaClass(clBean.getObject().getClass());
//            MyContainer.putBean(beanName,clBean1);
//            MyContainer.putAfterInjectBean(beanName, object);
//        });
//
//
//
//
//
//
//
//        //将收集到的待注入的所有bean进行注入
//        MyContainer.getControllerContainer().forEach((url, clController) -> {
//            //获取出方法对象,这个不能换掉
//            Method controllerMethod = clController.getControllerMethod();
//            Object object = injectClBean(url, clController.getObject().getClass());
//
//            //用相同的beanName , 把容器中对应的bean给替换掉,因为原来初始化的容器中的bean的需要注入属性都是没有注入的,都是null,
//            //经过这里注入后,替换为已经注入了属性的 bean
//            com.cl.container.ClController clController1 = new com.cl.container.ClController();
//            clController1.setUrl(url);
//            //Object替换掉 (替换为已经注入了属性的Object)
//            clController1.setObject(object);
//            //对应的method不替换
//            clController1.setControllerMethod(controllerMethod);
//            MyContainer.putClController(url,clController1);
//        });

    }


    static List<String> scan(File file, List<String> resultFileName) {
        File[] files = file.listFiles();
        if (files == null)
            return resultFileName;// 判断目录下是不是空的
        for (File f : files) {
            if (f.isDirectory()) {// 判断是否文件夹
                scan(f, resultFileName);// 调用自身,查找子目录
            } else
                //不是文件夹则添加到集合中
                resultFileName.add(f.getPath());
        }
        return resultFileName;
    }


    /*
     * 处理出class的全限定类名
     * */
    public static String filterQualifiedClassName(String fileName) {
        int i = fileName.indexOf("classes\\");
        String substring = fileName.substring(i + "classes\\".length());
        /*
         * 由于有转义 要\\\\才能匹配
         * */
        substring = substring.replaceAll("\\\\", ".");
        int i1 = substring.lastIndexOf(".");
        substring = substring.substring(0, i1);
        return substring;
    }


    public static Object injectClBean(String beanName, Class<?> clazs) {
        Object obj = null;
        if (clazs != null) {
            try {
                //此对象所需要的属性进行注入,返回此对象
                obj = createFieldBean(clazs);
            } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return obj;
        } else {
            throw new RuntimeException("clazs 不能为空");
        }
    }


    /*
    *创建bean
    * */
    public static ClBean preCreateBean(String beanName,Class<?> clazs) {
        Object obj = null;
        if (clazs != null) {
            ClBean clBean = new ClBean();
            clBean.setaClass(clazs);
            if (beanName.equals("") || beanName == null) {
                clBean.setBeanName(clazs.getSimpleName().toUpperCase());
            }else {
                clBean.setBeanName(beanName.toUpperCase());
            }
            try {
                //无参构造new对象
                obj = clazs.getDeclaredConstructor().newInstance();
            } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
            clBean.setObject(obj);

            /*
             * bean创建后回调后置处理器
             * 当此bean不是后置处理器时,而是一个普通的bean对象，创建完后，回调bean的后置处理器
             * */
            if (!(obj instanceof IBeanPostProcessor)) {
                //获取所有的bean后置处理器
                ConcurrentHashMap<String, Object> postProcessor = MyContainer.getPostProcessor();

                postProcessor.forEach((k, v) -> {
                    ClBean v1 = (ClBean) v;
                    /*
                     * 将此bean挨个经过 bean后置处理器
                     * */
                    IBeanPostProcessor iBeanPostProcessor = (IBeanPostProcessor) v1.getObject();
                    iBeanPostProcessor.postProcessor(clBean);
                });
            }

            //是否确定注入容器
            if (clBean.isInjectContainer()) {
                return clBean;
            }

            return null;
        } else {
            throw new RuntimeException("clazs 不能为空");
        }
    }


    private static Object createFieldBean(Class<?> clazs) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //创建此类对象 , 注入属性 , 返回对象
        Object o = clazs.getDeclaredConstructor().newInstance();
        Field[] declaredFields = clazs.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            ClComponent annotation = declaredField.getAnnotation(ClComponent.class);
            if (annotation != null) {
                if (annotation.isBean()) {
                    Class<?> type = declaredField.getType();
                    ClBean beanWithContainer = MyContainer.getBeanWithContainer(annotation.value(), type);
                    if (beanWithContainer != null){
                        declaredField.setAccessible(true);
                        declaredField.set(o, beanWithContainer.getObject());
                    }
                }
            }
        }
        return o;
    }


    public static void crateCoController(String url, Class clazz) {
       //一个 controller 的方法为 map 中的一个k,v
        //map中的 k (即url,要拼接上类上面的@ClController中的url
        Object o = null;
        try {
           o = clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            e.printStackTrace();
        }
        Method[] methods = clazz.getMethods();
        for (Method declaredMethod : methods) {
            //获取方法上的 @ClController 注解
            ClController annotation = declaredMethod.getAnnotation(ClController.class);
            if (annotation != null && !annotation.value().equals("") && annotation.isController()){
                com.cl.container.ClController clController = new com.cl.container.ClController();
                clController.setUrl(url+annotation.value());
                clController.setControllerMethod(declaredMethod);
                clController.setObject(o);
                MyContainer.putClController(url+annotation.value(),clController);
            }
        }
    }


    /*
    * 按照 order方法的返回值进行排序
    * */
    private static  List<DisposeClass> orderDisposeBean(List<DisposeClass> allDisposeClass){
        List<DisposeClass> collect = allDisposeClass.stream().sorted((dispose1, dispose2) -> {
            return dispose1.order() - dispose2.order();
        }).collect(Collectors.toList());
        return collect;
    }
}
